#include "ModelManager.h"

// Initialize the instance to null
ModelManager* ModelManager::m_ModelInstance = 0;

ModelManager::ModelManager(void)
{
	iModelIndex = 0;
}

ModelManager::~ModelManager(void)
{
}

ModelManager* ModelManager::GetInstance(void)
{
	// Create the instance if it doesn't exist
	if(!m_ModelInstance)
		m_ModelInstance = new ModelManager;

	// Return the singleton
	return m_ModelInstance;
}

void ModelManager::DeleteInstance(void)
{
	ModelManager::DestroyAllModels();
	// If instance exist, delete it!
	if(m_ModelInstance)
	{
		delete m_ModelInstance;
		m_ModelInstance = NULL;
	}
}

void ModelManager::InitModelManager(IDirect3DDevice9* m_pD3DDevice)
{
	// Get the device
	m_Device = m_pD3DDevice;

	// Initialize that we are going to the first track
	bFirstTrack = true;
	bJumping = false;
	bPausePath = false;

	// Set the timer variables
	iPathTimer = 0;
	lStartTime = (LONG)timeGetTime();
}

int ModelManager::LoadModel(LPCSTR xFileName, D3DXVECTOR3 vecPos, bool bPlacedin)
{
	// Create the struct for this sepcific model
	s_Model* currentModel = new s_Model;

	// Start .x loading
	LPD3DXBUFFER p_D3DXMtrlBuffer;
	currentModel->m_dwNumMaterials = 0;

	if(xFileName == "Models\\TurnTrk.X")
		currentModel->bCornerPiece = true;
	else
		currentModel->bCornerPiece = false;

	if(iModelIndex == 12)
		currentModel->bShielded = true;
	else
		currentModel->bShielded = false;

	// Load .x file
	D3DXLoadMeshFromX( xFileName, D3DXMESH_SYSTEMMEM,
		m_Device, NULL, &p_D3DXMtrlBuffer, NULL, &(currentModel->m_dwNumMaterials),
		&(currentModel->m_pMesh));

	D3DXMATERIAL* d3dxMaterials =
		(D3DXMATERIAL*)p_D3DXMtrlBuffer->GetBufferPointer();

	// Create an array based on the amount of materials we have
	currentModel->m_pMaterials = new D3DMATERIAL9[currentModel->m_dwNumMaterials];
	currentModel->m_pMeshTextures = new LPDIRECT3DTEXTURE9[currentModel->m_dwNumMaterials];

	// Load each material
	for( DWORD i = 0; i < currentModel->m_dwNumMaterials; i++)
	{
		currentModel->m_pMaterials[i] = d3dxMaterials[i].MatD3D;
		
		currentModel->m_pMaterials[i].Ambient = currentModel->m_pMaterials[i].Diffuse;

		currentModel->m_pMeshTextures[i] = NULL;
		if( d3dxMaterials[i].pTextureFilename)
			D3DXCreateTextureFromFile( m_Device,
				d3dxMaterials[i].pTextureFilename,
				&(currentModel->m_pMeshTextures[i]));
	}
	// End .x loading

	// Set the pos & scale for the model
	currentModel->vecScale = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
	currentModel->vecPos = vecPos;
	currentModel->vecRot = D3DXVECTOR3(0.0f, 0.0f, 0.0f);

	// Calculate and create the bounding boxes
	HRESULT hr = 0;
	BYTE* pVertices = 0;
	if( SUCCEEDED(currentModel->m_pMesh->LockVertexBuffer(0, (void**)&pVertices)))
	{
		// Locking the vertex buffer so we can compute the bounds
		hr = D3DXComputeBoundingBox((D3DXVECTOR3*)pVertices, currentModel->m_pMesh->GetNumVertices(),
			D3DXGetFVFVertexSize(currentModel->m_pMesh->GetFVF()), &currentModel->vecBBMin, 
			&currentModel->vecBBMax);

		// Unlock the vertex buffer
		currentModel->m_pMesh->UnlockVertexBuffer();

		// With the min and max vectors we can get the 8 corners for the bounding box
		currentModel->vecModelBounds[0] = D3DXVECTOR3(currentModel->vecBBMin.x, currentModel->vecBBMin.y, 
											currentModel->vecBBMin.z);
		currentModel->vecModelBounds[1] = D3DXVECTOR3(currentModel->vecBBMax.x, currentModel->vecBBMin.y, 
											currentModel->vecBBMin.z);
		currentModel->vecModelBounds[2] = D3DXVECTOR3(currentModel->vecBBMin.x, currentModel->vecBBMax.y, 
											currentModel->vecBBMin.z);
		currentModel->vecModelBounds[3] = D3DXVECTOR3(currentModel->vecBBMax.x, currentModel->vecBBMax.y, 
											currentModel->vecBBMin.z);
		currentModel->vecModelBounds[4] = D3DXVECTOR3(currentModel->vecBBMin.x, currentModel->vecBBMin.y, 
											currentModel->vecBBMax.z);
		currentModel->vecModelBounds[5] = D3DXVECTOR3(currentModel->vecBBMax.x, currentModel->vecBBMin.y, 
											currentModel->vecBBMax.z);
		currentModel->vecModelBounds[6] = D3DXVECTOR3(currentModel->vecBBMin.x, currentModel->vecBBMax.y, 
											currentModel->vecBBMax.z);
		currentModel->vecModelBounds[7] = D3DXVECTOR3(currentModel->vecBBMax.x, currentModel->vecBBMax.y, 
											currentModel->vecBBMax.z);
	}
	// If the exit is being loaded then create a sphere to be placed if there are mini games to be played.
	if(currentModel->bShielded)
	{
		// Create a shpere to serve as the shield
		D3DXCreateSphere(m_Device, 1.5f, 50, 50, &m_pShieldMesh, NULL);

		// Set material for shield
		ZeroMemory(&m_ShieldMat, sizeof(m_ShieldMat));
		m_ShieldMat.Ambient.r = 10.0f;
		m_ShieldMat.Ambient.g = 0.5f;
		m_ShieldMat.Ambient.b = 0.5f;
		m_ShieldMat.Diffuse.r = 0.0f;
		m_ShieldMat.Diffuse.g = 0.5f;
		m_ShieldMat.Diffuse.b = 0.0f;
		m_ShieldMat.Specular.r = 10.0f;
		m_ShieldMat.Specular.g = 0.5f;
		m_ShieldMat.Specular.b = 0.0f;
		m_ShieldMat.Emissive.r = 10.0f;
		m_ShieldMat.Emissive.g = 0.5f;
		m_ShieldMat.Emissive.b = 0.0f;
		m_ShieldMat.Power = 50.0f;

		// Calculate and create the bounding boxes
		currentModel->vecExtraBox = vecPos;
		HRESULT hr = 0;
		BYTE* pVertices = 0;
		if( SUCCEEDED(m_pShieldMesh->LockVertexBuffer(0, (void**)&pVertices)))
		{
			// Locking the vertex buffer so we can compute the bounds
			hr = D3DXComputeBoundingBox((D3DXVECTOR3*)pVertices, m_pShieldMesh->GetNumVertices(),
				D3DXGetFVFVertexSize(m_pShieldMesh->GetFVF()), &currentModel->vecExtraBBMin, 
				&currentModel->vecExtraBBMax);

			// Unlock the vertex buffer
			m_pShieldMesh->UnlockVertexBuffer();

			// With the min and max vectors we can get the 8 corners for the bounding box
			currentModel->vecExtraModelBounds[0] = D3DXVECTOR3(currentModel->vecExtraBBMin.x, currentModel->vecExtraBBMin.y, 
				currentModel->vecExtraBBMin.z);
			currentModel->vecExtraModelBounds[1] = D3DXVECTOR3(currentModel->vecExtraBBMax.x, currentModel->vecExtraBBMin.y, 
				currentModel->vecExtraBBMin.z);
			currentModel->vecExtraModelBounds[2] = D3DXVECTOR3(currentModel->vecExtraBBMin.x, currentModel->vecExtraBBMax.y, 
				currentModel->vecExtraBBMin.z);
			currentModel->vecExtraModelBounds[3] = D3DXVECTOR3(currentModel->vecExtraBBMax.x, currentModel->vecExtraBBMax.y, 
				currentModel->vecExtraBBMin.z);
			currentModel->vecExtraModelBounds[4] = D3DXVECTOR3(currentModel->vecExtraBBMin.x, currentModel->vecExtraBBMin.y, 
				currentModel->vecExtraBBMax.z);
			currentModel->vecExtraModelBounds[5] = D3DXVECTOR3(currentModel->vecExtraBBMax.x, currentModel->vecExtraBBMin.y, 
				currentModel->vecExtraBBMax.z);
			currentModel->vecExtraModelBounds[6] = D3DXVECTOR3(currentModel->vecExtraBBMin.x, currentModel->vecExtraBBMax.y, 
				currentModel->vecExtraBBMax.z);
			currentModel->vecExtraModelBounds[7] = D3DXVECTOR3(currentModel->vecExtraBBMax.x, currentModel->vecExtraBBMax.y, 
				currentModel->vecExtraBBMax.z);
		}
	}
	// If it is a corner piece then create extra box for empty space of sprite
	if(currentModel->bCornerPiece)
	{
		D3DXCreateBox(m_Device, 0.9f, 0.9f, 0.9f, &m_pExtraCollisionMesh, NULL);
		currentModel->vecCornerBoxTrans = D3DXVECTOR3(1.0f, 0.0f, -1.0f);
		currentModel->sCornerChange = 1;

		 // Calculate and create the bounding boxes
		HRESULT hr = 0;
		BYTE* pVertices = 0;
		if( SUCCEEDED(m_pExtraCollisionMesh->LockVertexBuffer(0, (void**)&pVertices)))
		{
			// Locking the vertex buffer so we can compute the bounds
			hr = D3DXComputeBoundingBox((D3DXVECTOR3*)pVertices, m_pExtraCollisionMesh->GetNumVertices(),
				D3DXGetFVFVertexSize(m_pExtraCollisionMesh->GetFVF()), &currentModel->vecExtraBBMin, 
				&currentModel->vecExtraBBMax);

			// Unlock the vertex buffer
			m_pExtraCollisionMesh->UnlockVertexBuffer();

			// With the min and max vectors we can get the 8 corners for the bounding box
			currentModel->vecExtraModelBounds[0] = D3DXVECTOR3(currentModel->vecExtraBBMin.x, currentModel->vecExtraBBMin.y, 
				currentModel->vecExtraBBMin.z);
			currentModel->vecExtraModelBounds[1] = D3DXVECTOR3(currentModel->vecExtraBBMax.x, currentModel->vecExtraBBMin.y, 
				currentModel->vecExtraBBMin.z);
			currentModel->vecExtraModelBounds[2] = D3DXVECTOR3(currentModel->vecExtraBBMin.x, currentModel->vecExtraBBMax.y, 
				currentModel->vecExtraBBMin.z);
			currentModel->vecExtraModelBounds[3] = D3DXVECTOR3(currentModel->vecExtraBBMax.x, currentModel->vecExtraBBMax.y, 
				currentModel->vecExtraBBMin.z);
			currentModel->vecExtraModelBounds[4] = D3DXVECTOR3(currentModel->vecExtraBBMin.x, currentModel->vecExtraBBMin.y, 
				currentModel->vecExtraBBMax.z);
			currentModel->vecExtraModelBounds[5] = D3DXVECTOR3(currentModel->vecExtraBBMax.x, currentModel->vecExtraBBMin.y, 
				currentModel->vecExtraBBMax.z);
			currentModel->vecExtraModelBounds[6] = D3DXVECTOR3(currentModel->vecExtraBBMin.x, currentModel->vecExtraBBMax.y, 
				currentModel->vecExtraBBMax.z);
			currentModel->vecExtraModelBounds[7] = D3DXVECTOR3(currentModel->vecExtraBBMax.x, currentModel->vecExtraBBMax.y, 
				currentModel->vecExtraBBMax.z);
		}
	 }
	// Player Model is set to true, set pieces set to false until they are placed on the game board.
	if (iModelIndex == 0)
		currentModel->bPlaced = true;
	else
		currentModel->bPlaced = bPlacedin; // Set to true for testing purposes
									// after testing needs to default to false

	// Insert the current structure into the vector
	modelList.push_back(currentModel);

	return iModelIndex++;
}

void ModelManager::DrawModel(void)
{	
	for(int i = 0; i < iModelIndex; i++)
	{
		if( modelList[i]->bPlaced )
		{
			// Reset the matrices
			D3DXMatrixIdentity( &modelList[i]->scaleMat);
			D3DXMatrixIdentity( &modelList[i]->rotMat);
			D3DXMatrixIdentity( &modelList[i]->transMat);
			D3DXMatrixIdentity( &modelList[i]->worldMat);

			// Rotate, scale, and move the .x drawing
			D3DXMatrixScaling( &modelList[i]->scaleMat, modelList[i]->vecScale.x, modelList[i]->vecScale.y, modelList[i]->vecScale.z);
			D3DXMatrixRotationYawPitchRoll( &modelList[i]->rotMat, modelList[i]->vecRot.x, modelList[i]->vecRot.y, modelList[i]->vecRot.z);
			D3DXMatrixTranslation( &modelList[i]->transMat, modelList[i]->vecPos.x, modelList[i]->vecPos.y, modelList[i]->vecPos.z);

			// Scale & rotation * translation
			D3DXMatrixMultiply( &modelList[i]->scaleMat, &modelList[i]->rotMat, &modelList[i]->scaleMat);
			D3DXMatrixMultiply( &modelList[i]->worldMat, &modelList[i]->scaleMat, &modelList[i]->transMat);

			m_Device->SetTransform( D3DTS_WORLD, &modelList[i]->worldMat);

			// Start .x drawing
			for( DWORD j = 0; j < modelList[i]->m_dwNumMaterials; j++)
			{
				m_Device->SetMaterial( &(modelList[i]->m_pMaterials[j]));
				m_Device->SetTexture( 0, (modelList[i]->m_pMeshTextures[j]));

				modelList[i]->m_pMesh->DrawSubset(j);
			}

			m_Device->SetTexture(0, NULL);
		}
		if(modelList[i]->bCornerPiece)
		{
			// Move extra collision box
			D3DXMatrixIdentity(&modelList[i]->extraTransMat);
			D3DXMatrixIdentity(&modelList[i]->extraWorldMat);
			D3DXMatrixTranslation(&modelList[i]->extraTransMat, modelList[i]->vecCornerBoxTrans.x, modelList[i]->vecCornerBoxTrans.y,
				modelList[i]->vecCornerBoxTrans.z);
			D3DXMatrixMultiply( &modelList[i]->scaleMat, &modelList[i]->scaleMat, &modelList[i]->transMat);
			D3DXMatrixMultiply( &modelList[i]->extraWorldMat, &modelList[i]->scaleMat, &modelList[i]->extraTransMat);

			m_Device->SetTransform( D3DTS_WORLD, &modelList[i]->extraWorldMat);

			//m_pExtraCollisionMesh->DrawSubset(0);
		}
		if(modelList[i]->bShielded)
		{
			D3DXMatrixIdentity(&modelList[i]->extraWorldMat);
			D3DXMatrixMultiply( &modelList[i]->scaleMat, &modelList[i]->scaleMat, &modelList[i]->transMat);
			D3DXMatrixMultiply( &modelList[i]->extraWorldMat, &modelList[i]->scaleMat, &modelList[i]->rotMat);

			m_Device->SetTransform( D3DTS_WORLD, &modelList[i]->extraWorldMat);
			m_Device->SetMaterial(&m_ShieldMat);
			m_pShieldMesh->DrawSubset(0);
		}
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		//		Testing code!!!!      Drawing Bounding Box to ensure it is correcly placed on model
		//// Turning on Wireframe
		//m_Device->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );

		//// get attributes to draw bounding box
		//float width, height, depth;
		//width = modelList[i]->vecBBMax.x - modelList[i]->vecBBMin.x;
		//height = modelList[i]->vecBBMax.y - modelList[i]->vecBBMin.y;
		//depth = modelList[i]->vecBBMax.z - modelList[i]->vecBBMin.z;

		//// Make a mesh
		//D3DXCreateBox( m_Device, width, height, depth, &m_pBBmesh, NULL);
		//// Draw box
		//m_pBBmesh->DrawSubset(0);

		//// Turn off WireFrame
		//m_Device->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	}
}

D3DXVECTOR3 ModelManager::GetPlayerPos(void)
{
	return modelList[0]->vecPos;
}

bool ModelManager::GetBCornerPiece(int iModelID)
{
	return modelList[iModelID]->bCornerPiece;
}

D3DXVECTOR3 ModelManager::GetModelPos(int iModelID)
{
	return modelList[iModelID]->vecPos;
}

bool ModelManager::GetModelPlaced(int iModelID)
{
	return modelList[iModelID]->bPlaced;
}

void ModelManager::ModifyModelPos(int iModelID, float fXChange, float fYChange, float fZChange)
{
	// Change the position based on the values received
	modelList[iModelID]->vecPos.x += fXChange;
	modelList[iModelID]->vecPos.y += fYChange;
	modelList[iModelID]->vecPos.z += fZChange;
}

void ModelManager::PlaceTrack(int iModelID, float fXChange, float fYChange, float fZChange, bool bPlacedin, bool bFightMode )
{
	// Actually place the track based on the mouse position sent in
	modelList[iModelID]->vecPos.x = fXChange;
	modelList[iModelID]->vecPos.z = fZChange;
	modelList[iModelID]->bPlaced = bPlacedin;
	if(!bFightMode)
	{
		if(modelList[iModelID - 1]->vecPos.y == 0.0f || modelList[iModelID - 1]->vecPos.y == -0.014f)
			modelList[iModelID]->vecPos.y = -0.01f;
		else
			modelList[iModelID]->vecPos.y = -0.014f;
	}
	else
	{
		if(modelList[iModelID - 1]->vecPos.y == 10.0f || modelList[iModelID - 1]->vecPos.y == 9.994f)
			modelList[iModelID]->vecPos.y = 9.99f;
		else
			modelList[iModelID]->vecPos.y = 9.994f;
	}
}

void ModelManager::ResetPlayer(short sCheckpoint)
{
	modelList[0]->vecPos.x = modelList[sCheckpoint]->vecPos.x;
	modelList[0]->vecPos.y = modelList[sCheckpoint]->vecPos.y + 5.0f;
	modelList[0]->vecPos.z = modelList[sCheckpoint]->vecPos.z;
}

void ModelManager::ModifyModelRot(int iModelID, float fXChange, float fYChange, float fZChange)
{
	//Change the Rotation of the Track piece based on user inputs
	modelList[iModelID]->vecRot.x += fXChange;
	modelList[iModelID]->vecRot.y += fYChange;
	modelList[iModelID]->vecRot.z += fZChange;
	if(modelList[iModelID]->bCornerPiece)
	{
		++modelList[iModelID]->sCornerChange; 
		if(modelList[iModelID]->sCornerChange > 4)
			modelList[iModelID]->sCornerChange = 1;
		switch(modelList[iModelID]->sCornerChange)
		{
		case 1:
			modelList[iModelID]->vecCornerBoxTrans.x = 1.0f;
			modelList[iModelID]->vecCornerBoxTrans.y = 0.0f;
			modelList[iModelID]->vecCornerBoxTrans.z = -1.0f;
			break;
		case 2:
			modelList[iModelID]->vecCornerBoxTrans.x = 1.0f;
			modelList[iModelID]->vecCornerBoxTrans.y = 0.0f;
			modelList[iModelID]->vecCornerBoxTrans.z = 1.0f;
			break;
		case 3:
			modelList[iModelID]->vecCornerBoxTrans.x = -1.0f;
			modelList[iModelID]->vecCornerBoxTrans.y = 0.0f;
			modelList[iModelID]->vecCornerBoxTrans.z = 1.0f;
			break;
		case 4:
			modelList[iModelID]->vecCornerBoxTrans.x = -1.0f;
			modelList[iModelID]->vecCornerBoxTrans.y = 0.0f;
			modelList[iModelID]->vecCornerBoxTrans.z = -1.0f;
			break;
		default:
			break;
		}
	}
}
//***********************************************************************************************************
void ModelManager::RunPath(int iPreLoaded, int iLastTrack, float fDeltaTime)
{
	if(bFirstTrack)
	{
		//iPathTimer = 0;
		iDestination = iPreLoaded + 1;
	}

	if(iDestination != iLastTrack + 1)
	{
		// Calculate the distance between the destination orb and the player
		vecDistance.x = modelList[iDestination]->vecPos.x - modelList[0]->vecPos.x;
		vecDistance.y = modelList[iDestination]->vecPos.y - modelList[0]->vecPos.y;
		vecDistance.z = modelList[iDestination]->vecPos.z - modelList[0]->vecPos.z;

		if(vecDistance.z < 5.0f)
		{
			// RUN THE PATH
			if(!bPausePath)
			{
				if(!bJumping)
				{
					// Start moving the player towards the destination orb
					modelList[0]->vecPos.x += vecDistance.x * 3.0f * fDeltaTime;
					modelList[0]->vecPos.y += vecDistance.y * 3.0f * fDeltaTime;
					modelList[0]->vecPos.z += vecDistance.z * 3.0f * fDeltaTime;
				}
				else
				{
					if(modelList[0]->vecPos.y < fMaxJump)
					{
						modelList[0]->vecPos.x += vecDistance.x * 3.0f * fDeltaTime;
						modelList[0]->vecPos.y += 5.0f * fDeltaTime;
						modelList[0]->vecPos.z += vecDistance.z * 3.0f * fDeltaTime;
					}
					else
						bJumping = false;
				}
			}
		}
		if(CollisionDetection(iDestination))
		{
			if(iDestination != iLastTrack)
			{
				if(modelList[iDestination]->sTypeID == 0)
				{
					// It is a white orb so move on to the next one
					iDestination += 1;
					// Set the timer back to 0
					// Once we start going to the next track
					iPathTimer = 0;
					bJumping = false;
					bFirstTrack = false;
				}
				else if(modelList[iDestination]->sTypeID == 1)
				{
					// Blur orb, pause the path
					bPausePath = true;
					iDestination += 1;
					// Set the timer back to 0
					// Once we start going to the next track
					iPathTimer = 0;
					bJumping = false;
					bFirstTrack = false;
				}
				else if(modelList[iDestination]->sTypeID == 2)
				{
					// Red Orb, jump over to the next orb
					vecMidpoint.x = (modelList[iDestination]->vecPos.x + modelList[iDestination + 1]->vecPos.x) / 2;
					vecMidpoint.y = 3.0f;
					vecMidpoint.z = (modelList[iDestination]->vecPos.z + modelList[iDestination + 1]->vecPos.z) / 2;
					iDestination += 1;
					// Set the timer back to 0
					// Once we start going to the next track
					iPathTimer = 0;
					bJumping = true;
					bFirstTrack = false;
					fMaxJump = 13.0f;
				}
			}
			if(!bPausePath)
			{
				lCurrentTime = (LONG)timeGetTime();
				lCurrentTime -= lStartTime;

				if(lCurrentTime > 1000)
				{
					iPathTimer++;
					lStartTime = (LONG)timeGetTime();
				}
			}
		}
	}
}

int ModelManager::CheckPathTime(void)
{
	return iPathTimer;
}

void ModelManager::SetTypeID(int iTrackID, short iTypeID)
{
	modelList[iTrackID]->sTypeID = iTypeID;
}
//***********************************************************************************************************
// If all or no mini games in a level then turn off shield
void ModelManager::CheckShieldStatus(short sMiniGameCount)
{
	if(sMiniGameCount == 0)
	{
		// modelList[12] should always be the exit door
		modelList[12]->bShielded = false;
	}
}

void ModelManager::CalculateWorldBB(int iModelID)
{
	// Convert Object's model space bounding box to world space
	// Transform the 8 corners of our object space bounding box into world space
	D3DXVECTOR3 worldBounds[8];
	for( int i = 0; i < 8; i++)
		D3DXVec3TransformCoord( &worldBounds[i], &modelList[iModelID]->vecModelBounds[i], &modelList[iModelID]->worldMat );

	// Pick a corner and set the smallest point and largest point to that corner
	modelList[iModelID]->worldBBmin = worldBounds[0];
	modelList[iModelID]->worldBBmax = worldBounds[0];

	// Find the new minimum and maximum points after transformation
	// Now, compare the other corners and see if they are smaller or larger
	for( short i = 1; i < 8; i++ )
	{
		if(worldBounds[i].x < modelList[iModelID]->worldBBmin.x)
			modelList[iModelID]->worldBBmin.x = worldBounds[i].x;
		if(worldBounds[i].x > modelList[iModelID]->worldBBmax.x)
			modelList[iModelID]->worldBBmax.x = worldBounds[i].x;
		if(worldBounds[i].y < modelList[iModelID]->worldBBmin.y)
			modelList[iModelID]->worldBBmin.y = worldBounds[i].y;
		if(worldBounds[i].y > modelList[iModelID]->worldBBmax.y)
			modelList[iModelID]->worldBBmax.y = worldBounds[i].y;
		if(worldBounds[i].z < modelList[iModelID]->worldBBmin.z)
			modelList[iModelID]->worldBBmin.z = worldBounds[i].z;
		if(worldBounds[i].z > modelList[iModelID]->worldBBmax.z)
			modelList[iModelID]->worldBBmax.z = worldBounds[i].z;	
	}
}

bool ModelManager::CollisionDetection(int iModelID)
{
	// Calculate the world space bounding box for player object
	CalculateWorldBB(0);

	// Calculate the world space bounding box for other object
	CalculateWorldBB(iModelID);

	// Collision check on the boundaries
	if(modelList[0]->worldBBmax.x < modelList[iModelID]->worldBBmin.x)
		return false;
	if(modelList[0]->worldBBmax.y < modelList[iModelID]->worldBBmin.y)
		return false;
	if(modelList[0]->worldBBmax.z < modelList[iModelID]->worldBBmin.z)
		return false;
	if(modelList[0]->worldBBmin.x > modelList[iModelID]->worldBBmax.x)
		return false;
	if(modelList[0]->worldBBmin.y > modelList[iModelID]->worldBBmax.y)
		return false;
	if(modelList[0]->worldBBmin.z > modelList[iModelID]->worldBBmax.z)
		return false;

	// Collision occured
	return true;
}

void ModelManager::CalculateExtraBB(int iModelID)
{
	// Calculate additional world space for the corner track's empty space
	D3DXVECTOR3 worldBounds[8];
	for( int i = 0; i < 8; i++)
		D3DXVec3TransformCoord( &worldBounds[i], &modelList[iModelID]->vecExtraModelBounds[i], &modelList[iModelID]->extraWorldMat );

	// Pick a corner and set the smallest point and largest point to that corner
	modelList[iModelID]->vecExtraWorldBBmin = worldBounds[0];
	modelList[iModelID]->vecExtraWorldBBmax = worldBounds[0];

	// Find the new minimum and maximum points after transformation
	// Now, compare the other corners and see if they are smaller or larger
	for( short i = 1; i < 8; i++ )
	{
		if(worldBounds[i].x < modelList[iModelID]->vecExtraWorldBBmin.x)
			modelList[iModelID]->vecExtraWorldBBmin.x = worldBounds[i].x;
		if(worldBounds[i].x > modelList[iModelID]->vecExtraWorldBBmax.x)
			modelList[iModelID]->vecExtraWorldBBmax.x = worldBounds[i].x;
		if(worldBounds[i].y < modelList[iModelID]->vecExtraWorldBBmin.y)
			modelList[iModelID]->vecExtraWorldBBmin.y = worldBounds[i].y;
		if(worldBounds[i].y > modelList[iModelID]->vecExtraWorldBBmax.y)
			modelList[iModelID]->vecExtraWorldBBmax.y = worldBounds[i].y;
		if(worldBounds[i].z < modelList[iModelID]->vecExtraWorldBBmin.z)
			modelList[iModelID]->vecExtraWorldBBmin.z = worldBounds[i].z;
		if(worldBounds[i].z > modelList[iModelID]->vecExtraWorldBBmax.z)
			modelList[iModelID]->vecExtraWorldBBmax.z = worldBounds[i].z;	
	}
}

bool ModelManager::CornerCollision(int iModelID)
{
	// Calculate the world space bounding box for player object
	CalculateWorldBB(0);
	// get World BB for Corner piece's additional collision
	CalculateExtraBB(iModelID); 

	// Collision check on the boundaries
	if(modelList[0]->worldBBmax.x < modelList[iModelID]->vecExtraWorldBBmin.x)
		return false;
	if(modelList[0]->worldBBmax.y < modelList[iModelID]->vecExtraWorldBBmin.y)
		return false;
	if(modelList[0]->worldBBmax.z < modelList[iModelID]->vecExtraWorldBBmin.z)
		return false;
	if(modelList[0]->worldBBmin.x > modelList[iModelID]->vecExtraWorldBBmax.x)
		return false;
	if(modelList[0]->worldBBmin.y > modelList[iModelID]->vecExtraWorldBBmax.y)
		return false;
	if(modelList[0]->worldBBmin.z > modelList[iModelID]->vecExtraWorldBBmax.z)
		return false;

	// collision detected
	return true;
}

bool ModelManager::ShieldCollision(void)
{
	// if shield is not up then don't bother with collision
	if(modelList[12]->bShielded)
	{
		// Calculate the world space bounding box for player object
		CalculateWorldBB(0);
		// get World BB for Corner piece's additional collision
		CalculateExtraBB(12); 

		// Collision check on the boundaries
		if(modelList[0]->worldBBmax.x < modelList[12]->vecExtraWorldBBmin.x)
			return false;
		if(modelList[0]->worldBBmax.y < modelList[12]->vecExtraWorldBBmin.y)
			return false;
		if(modelList[0]->worldBBmax.z < modelList[12]->vecExtraWorldBBmin.z)
			return false;
		if(modelList[0]->worldBBmin.x > modelList[12]->vecExtraWorldBBmax.x)
			return false;
		if(modelList[0]->worldBBmin.y > modelList[12]->vecExtraWorldBBmax.y)
			return false;
		if(modelList[0]->worldBBmin.z > modelList[12]->vecExtraWorldBBmax.z)
			return false;

		// collision detected
		return true;
	}
	return false;
}
bool ModelManager::TrackPlacementCollision(int iCurrentTrack, int iModelID)
{
	if(iCurrentTrack != iModelID)
	{
		// Calculate the world space bounding box for player object
		CalculateWorldBB(iCurrentTrack);

		// Calculate the world space bounding box for other object
		CalculateWorldBB(iModelID);

		// Collision check on the boundaries
		if(modelList[iCurrentTrack]->worldBBmax.x < modelList[iModelID]->worldBBmin.x)
			return false;
		if(modelList[iCurrentTrack]->worldBBmax.y < modelList[iModelID]->worldBBmin.y)
			return false;
		if(modelList[iCurrentTrack]->worldBBmax.z < modelList[iModelID]->worldBBmin.z)
			return false;
		if(modelList[iCurrentTrack]->worldBBmin.x > modelList[iModelID]->worldBBmax.x)
			return false;
		if(modelList[iCurrentTrack]->worldBBmin.y > modelList[iModelID]->worldBBmax.y)
			return false;
		if(modelList[iCurrentTrack]->worldBBmin.z > modelList[iModelID]->worldBBmax.z)
			return false;

		// Collision occured
		return true;
	}
	// No collision occured
	return false;
}

void ModelManager::DestroyModel(int iModelID)
{
	/////////////////////////////////////////////////////////////////////////////
	// .x file deleting
	if(modelList[iModelID]->m_pMaterials != NULL)
	{
		delete modelList[iModelID]->m_pMaterials;
	}

	if(modelList[iModelID]->m_pMeshTextures)
	{
		for(DWORD j = 0; j < modelList[iModelID]->m_dwNumMaterials; j++)
		{
			if(modelList[iModelID]->m_pMeshTextures[j])
			{
				modelList[iModelID]->m_pMeshTextures[j]->Release();
				modelList[iModelID]->m_pMeshTextures[j] = NULL;
			}
		}

		delete[] modelList[iModelID]->m_pMeshTextures;
	}

	if(modelList[iModelID]->m_pMesh)
	{
		modelList[iModelID]->m_pMesh->Release();
		modelList[iModelID]->m_pMesh = NULL;
	}
	/////////////////////////////////////////////////////////////////////////////
	delete modelList[iModelID];
	modelList[iModelID] = NULL;

	iModelIndex--;
	modelList.pop_back();
}

void ModelManager::DestroyAllModels(void)
{
	/////////////////////////////////////////////////////////////////////////////
	// .x file deleting
	for(int i = iModelIndex - 1; i >= 0; i--)
	{
		if(modelList[i]->m_pMaterials != NULL)
		{
			delete modelList[i]->m_pMaterials;
			modelList[i]->m_pMaterials = NULL;
		}

		if(modelList[i]->m_pMeshTextures)
		{
			for(DWORD j = 0; j < modelList[i]->m_dwNumMaterials; j++)
			{
				if(modelList[i]->m_pMeshTextures[j])
				{
					modelList[i]->m_pMeshTextures[j]->Release();
					modelList[i]->m_pMeshTextures[j] = NULL;
				}
			}

			delete[] modelList[i]->m_pMeshTextures;
			modelList[i]->m_pMeshTextures = NULL;
		}

		if(modelList[i]->m_pMesh)
		{
			modelList[i]->m_pMesh->Release();
			modelList[i]->m_pMesh = NULL;
		}
		/////////////////////////////////////////////////////////////////////////////
		delete modelList[i];
		modelList[i] = NULL;
		modelList.pop_back();
	}
	iModelIndex = 0;
}